package com.xbongbong.paas.help;

import com.alibaba.fastjson.JSON;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.elasticsearch.model.PaasFormDataEsModel;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.pojo.dto.FormDataRepeatDTO;
import com.xbongbong.paas.pojo.vo.CheckRepeatVO;
import com.xbongbong.paas.pojo.vo.FormDataRepeatVO;
import com.xbongbong.paas.service.recheck.AbstractRecheckAddEditStrategy;
import com.xbongbong.paas.service.recheck.RecheckAddRuleFactory;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.user.pojo.ReturnUserAndDepartmentPojo;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ContractEnum;
import com.xbongbong.saas.enums.business.ProductEnum;
import com.xbongbong.saas.enums.business.QuotationEnum;
import com.xbongbong.saas.enums.business.SupplierEnum;
import com.xbongbong.saas.enums.business.WorkOrderEnum;
import com.xbongbong.saas.help.CompetitorHelp;
import com.xbongbong.saas.model.IndexTypeModel;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

@Component
public class RepeatHelp {

    private static final Logger LOG = LoggerFactory.getLogger(RepeatHelp.class);

    @Resource
    private EsHelper esHelper;
    @Resource
    private PaasFormDataEsModel paasFormDataEsModel;
    @Resource
    private CommonHelp commonHelp;
    @Resource
    private IndexTypeModel indexTypeModel;
    @Resource
    private RecheckAddRuleFactory recheckAddRuleFactory;
    @Resource
    private CompetitorHelp competitorHelp;

    public CheckRepeatVO repeat(FormDataRepeatDTO formDataRepeatDTO) throws XbbException {
        CheckRepeatVO checkRepeatVO = new CheckRepeatVO();
        checkRepeatVO.setNoRepeat(true);
        try {
            if(Objects.equals(formDataRepeatDTO.getBusinessType(),XbbRefTypeEnum.COMPETITOR_ANALYSIS.getCode())){
                // 竞争对手分析比较特殊
                return competitorHelp.repeat(formDataRepeatDTO);
            }
            // 非流水号字段如果value为空或者null，不需要校验是否重复
            Boolean isEmpty = formDataRepeatDTO.getValue() == null || StringUtil.isEmpty(formDataRepeatDTO.getValue().toString());
            if ( isEmpty && StringUtil.isEmpty(formDataRepeatDTO.getSerialNo()) ) {
                return checkRepeatVO;
            }
            String corpid = formDataRepeatDTO.getCorpid();
            String subAttr = formDataRepeatDTO.getSubAttr();
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            BoolQueryBuilder boolQueryBuilder = boolQuery();
            boolQueryBuilder.filter(termQuery("formId", formDataRepeatDTO.getFormId()));
            boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
            if (StringUtil.isEmpty(subAttr)) {
                // 子表单无需搜索appId
                boolQueryBuilder.filter(termQuery("appId", formDataRepeatDTO.getAppId()));
            }
            if ( formDataRepeatDTO.getValue() instanceof Map ) {
                // 处理人员或者部门的数据
                ReturnUserAndDepartmentPojo linkData = JSON.parseObject(JSON.toJSONString(formDataRepeatDTO.getValue()), ReturnUserAndDepartmentPojo.class);
                if ( Objects.nonNull(linkData) ) {
                    formDataRepeatDTO.setValue(linkData.getId());
                }
            }
            Integer businessType = formDataRepeatDTO.getBusinessType();
            boolean recheckFlag = XbbRefTypeEnum.checkRecheckRuleBusinessType(businessType);
            //是线索、客户、联系人机会走查重2.0逻辑
            if (recheckFlag){
                AbstractRecheckAddEditStrategy recheckAddEditStrategy = recheckAddRuleFactory.getRecheckAddEditStrategy(formDataRepeatDTO.getBusinessType());
                return recheckAddEditStrategy.abstractExecuteRule(formDataRepeatDTO);
            }

            if ( StringUtil.isEmpty(formDataRepeatDTO.getSerialNo()) ) {
                // 工单联系方式查重特殊处理
                if ((Objects.equals(businessType, XbbRefTypeEnum.WORK_ORDER.getCode()) || Objects.equals(businessType, XbbRefTypeEnum.WORK_ORDER_V2.getCode())) && Objects.equals(formDataRepeatDTO.getAttr(), WorkOrderEnum.CONTACT_INFORMATION.getAttr()) && Objects.equals(formDataRepeatDTO.getSubAttr(), "text_2")) {
                    String attr = StringConstant.JSON_DATA + StringConstant.POINT + formDataRepeatDTO.getAttr() + StringConstant.POINT + formDataRepeatDTO.getSubAttr();
                    boolQueryBuilder.filter(termQuery(attr, formDataRepeatDTO.getValue()));
                    if (!Objects.isNull(formDataRepeatDTO.getDataId())) {
                        boolQueryBuilder.mustNot(termQuery(BasicConstant.DATAID, formDataRepeatDTO.getDataId()));
                    }
                } else {
                    String attr = "data." + formDataRepeatDTO.getAttr();
                    if ( StringUtil.isNotEmpty(subAttr)  && !(Objects.equals(XbbRefTypeEnum.SUPPLIER.getCode(),formDataRepeatDTO.getBusinessType()) && Objects.equals(SupplierEnum.PHONE.getAttr(),formDataRepeatDTO.getAttr()))) {
                        attr = "data." + formDataRepeatDTO.getSubAttr();
                        boolQueryBuilder.filter(termQuery("attr.keyword", formDataRepeatDTO.getAttr()));
                    }
                    attr = attr + ".keyword";
                    if ( formDataRepeatDTO.getValue() instanceof ReturnUserAndDepartmentPojo ) {
                        // 校验员工单选
                        ReturnUserAndDepartmentPojo returnUserAndDepartmentPojo = (ReturnUserAndDepartmentPojo) formDataRepeatDTO.getValue();
                        boolQueryBuilder.filter(termQuery(attr, returnUserAndDepartmentPojo.getId()));
                    } else {
                        // TODO 不知道什么原因供应商电话故意放到主表中了 所以只好暂时特殊处理了
                        if ((Objects.equals(XbbRefTypeEnum.SUPPLIER.getCode(),formDataRepeatDTO.getBusinessType())) && Objects.equals(SupplierEnum.PHONE.getAttr(),formDataRepeatDTO.getAttr())){
                            attr = "data." + formDataRepeatDTO.getAttr() + "." + formDataRepeatDTO.getSubAttr() + ".keyword";
                            Long dataId = formDataRepeatDTO.getDataId();
                            if (Objects.nonNull(dataId)){
                                boolQueryBuilder.mustNot(termQuery("dataId", dataId));
                            }
                        }
                        boolQueryBuilder.filter(termQuery(attr, formDataRepeatDTO.getValue()));
                    }
                }
            } else {
                // 编号
                String serialNoAttr = FieldTypeEnum.SERIALNO.getAlias() + StringConstant.POINT + StringConstant.KEY_WORD;
                boolQueryBuilder.filter(termQuery(serialNoAttr, formDataRepeatDTO.getSerialNo()));
            }
            // 客户回收站也要查重
            if ( Objects.equals(businessType, XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode()) || Objects.equals(businessType, XbbRefTypeEnum.CLUE.getCode())) {
                boolQueryBuilder.filter(termsQuery(ParameterConstant.DEL, Arrays.asList(DelEnum.NORMAL.getDel(), DelEnum.DELETE.getDel())));
            } else {
                boolQueryBuilder.filter(termQuery(ParameterConstant.DEL, DelEnum.NORMAL.getDel()));
            }
            if ( Objects.equals(businessType, XbbRefTypeEnum.PRODUCT.getCode()) ) {
                boolQueryBuilder.filter(termQuery(ProductEnum.getAttrConnectData(ProductEnum.PARENT_ID), 0));
            } else if (Objects.equals(XbbRefTypeEnum.CONTRACT.getCode(), businessType)) {
                // fix-bug：32530 合同校验， 需要去掉红冲合同
                boolQueryBuilder.filter(termQuery(ContractEnum.getAttrConnectData(ContractEnum.IS_RED), 0));
            }
            // 期初编号的查重条件为公司维度
            if (Objects.equals(businessType,XbbRefTypeEnum.ORI_STOCK.getCode())){
                esHelper.removeSearchCondition(boolQueryBuilder, "formId");
                esHelper.removeSearchCondition(boolQueryBuilder, "appId");
            }
            boolean quotationNameRepeat = Objects.equals(businessType, XbbRefTypeEnum.QUOTATION.getCode())
                    && Objects.equals(formDataRepeatDTO.getAttr(), QuotationEnum.NAME.getAttr());
            if ( quotationNameRepeat ) {
                // 报价单保存时，名称校验只校验最新版本的报价单
                boolQueryBuilder.filter(termQuery(QuotationEnum.getAttrConnectData(QuotationEnum.IS_NEW), BasicConstant.ONE));
            }
            /**
             * 逻辑梳理:
             *
             * 原逻辑:
             * 客户：审批中数据 + 主表正常数据
             * 其他：主表正常数据
             *
             * 现逻辑：
             * 客户：
             * 	没有开启工作流流   	审批中数据 + 主表正常数据
             * 	开启工作流       	主表正常数据 + 主表审批中数据
             * 其他：主表正常数据
             */
            if (StringUtil.isEmpty(subAttr)) {
                if (Objects.equals(formDataRepeatDTO.getBusinessType(),XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode()) && commonHelp.isOpenWorkFlow(formDataRepeatDTO.getCorpid())) {
                    boolQueryBuilder.filter(termsQuery("flowStatus", Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(),FlowStatusEnum.PASS.getType(), FlowStatusEnum.APPROVAL_PENDING.getType(),FlowStatusEnum.IN_APPROVAL.getType())));
                } else {
                    boolQueryBuilder.filter(termsQuery("flowStatus", Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(),FlowStatusEnum.PASS.getType())));
                }
            }

            // 联系人电话判重，剔除此次提交的所有数据，本次提交表单内数据判重已在前面处理，bugId:33659
            if (Objects.equals(businessType, XbbRefTypeEnum.CONTACT.getCode()) && CollectionsUtil.isNotEmpty(formDataRepeatDTO.getContactDataIdSet())) {
                boolQueryBuilder.mustNot(termsQuery(BasicConstant.DATAID, formDataRepeatDTO.getContactDataIdSet()));
            }
            Integer saasMark = formDataRepeatDTO.getSaasMark();

            IndexTypeEnum indexTypeEnum = indexTypeModel.getIndexType(formDataRepeatDTO.getCorpid(),  businessType, saasMark);
            if (Objects.equals(businessType, XbbRefTypeEnum.WORK_ORDER.getCode()) || Objects.equals(businessType, XbbRefTypeEnum.WORK_ORDER_V2.getCode())) {
                // 工单联系方式查重特殊处理
                if (!(Objects.equals(formDataRepeatDTO.getAttr(), WorkOrderEnum.CONTACT_INFORMATION.getAttr()) && Objects.equals(formDataRepeatDTO.getSubAttr(), "text_2"))) {
                    if (StringUtil.isNotEmpty(formDataRepeatDTO.getSubAttr())) {
                        indexTypeEnum = indexTypeModel.getSubIndexType(formDataRepeatDTO.getCorpid(), businessType, saasMark);
                    }
                }
            } else {
                // TODO 不知道什么原因供应商电话故意放到主表中了 所以只好暂时特殊处理了
                if (StringUtil.isNotEmpty(formDataRepeatDTO.getSubAttr())  && !(Objects.equals(XbbRefTypeEnum.SUPPLIER.getCode(),formDataRepeatDTO.getBusinessType()) && Objects.equals(SupplierEnum.PHONE.getAttr(),formDataRepeatDTO.getAttr()))) {
                    indexTypeEnum = indexTypeModel.getSubIndexType(formDataRepeatDTO.getCorpid(), businessType, saasMark);
                }
            }
            boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD,indexTypeEnum.getType()));
            sourceBuilder.query(boolQueryBuilder);
            SearchRequest searchRequest = new SearchRequest(indexTypeEnum.getIndex());
            //TODO 没找到page相关的代码，默认查询20条 2019年6月27日11:08:03
            PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, 10);
            searchRequest.source(sourceBuilder);
            FormDataRepeatVO formDataRepeatVO = paasFormDataEsModel.repeat(pageRequest, searchRequest);
            List<PaasFormDataEntityExt> formDataList = formDataRepeatVO.getFormDataList();
            if ( !formDataList.isEmpty() ) {
                checkRepeatVO.setNoRepeat(false);
                Boolean newVersionNameRepeat = quotationNameRepeat && Objects.equals(formDataRepeatDTO.getNewVersion(), BasicConstant.ONE) && Objects.nonNull(formDataRepeatDTO.getGroupNumber());
                if ( newVersionNameRepeat ) {
                    // 报价单新版本同一组号的名称不作校验
                    Integer repeatNum = 0;
                    String groupNumber = formDataRepeatDTO.getGroupNumber();
                    for ( PaasFormDataEntityExt entityExt : formDataList ) {
                        String gNumber = FastJsonHelper.getStringOrDefaultFromFormData(entityExt.getData(), QuotationEnum.GROUP_NUMBER.getAttr(), "");
                        if ( !Objects.equals(groupNumber, gNumber) ) {
                            repeatNum++;
                        }
                    }
                    if ( repeatNum == 0 ) {
                        checkRepeatVO.setNoRepeat(true);
                    }
                    return checkRepeatVO;
                }
                if ( formDataList.size() == 1 && StringUtil.isEmpty(subAttr) && Objects.equals(formDataList.get(0).getId(), formDataRepeatDTO.getDataId()) ) {
                    checkRepeatVO.setNoRepeat(true);
                }else if ( formDataList.size() == 1 && StringUtil.isNotEmpty(subAttr) && Objects.equals(formDataList.get(0).getId(), formDataRepeatDTO.getSubDataId()) ) {
                    // 判断子表单数据是否重复
                    checkRepeatVO.setNoRepeat(true);
                }
                if ( formDataList.size() > 1 ) {
                    checkRepeatVO.setManyRepeat(true);
                }
            }
        } catch (XbbException xe) {
            throw xe;
        } catch (Exception e) {
            LOG.error("paasFormData.repeat查询数据重复出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return checkRepeatVO;
    }

    public FormDataRepeatVO importRepeat(FormDataRepeatDTO formDataRepeatDTO, Map<String, Object> repeatValueMap) throws XbbException {
        FormDataRepeatVO formDataRepeatVO = null;
        formDataRepeatDTO.setIsImport(true);
        try {
            formDataRepeatVO = new FormDataRepeatVO();
            List<PaasFormDataEntityExt> repeatDataList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Set<Map.Entry<String, Object>> entrySet = repeatValueMap.entrySet();
            Iterator<Map.Entry<String, Object>> iterator = entrySet.iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, Object> entry = iterator.next();
                String attr = entry.getKey();
                Object value = entry.getValue();
                if (attr.contains(StringConstant.COMMA)) {
                    String attrField = attr.split(StringConstant.COMMA)[0];
                    String subAttrField = attr.split(StringConstant.COMMA)[1];
                    formDataRepeatDTO.setAttr(attrField);
                    formDataRepeatDTO.setSubAttr(subAttrField);
                    formDataRepeatDTO.setValue(value);
                } else {
                    formDataRepeatDTO.setAttr(attr);
                    formDataRepeatDTO.setValue(value);
                    formDataRepeatDTO.setSubAttr(null);
                }
                AbstractRecheckAddEditStrategy recheckAddEditStrategy = recheckAddRuleFactory.getRecheckAddEditStrategy(formDataRepeatDTO.getBusinessType());
                CheckRepeatVO checkRepeatVO = recheckAddEditStrategy.abstractExecuteRule(formDataRepeatDTO);
                List<PaasFormDataEntityExt> formDataList = checkRepeatVO.getFormDataList();
                repeatDataList.addAll(formDataList);
            }
            ArrayList<PaasFormDataEntityExt> dataEntityExts = repeatDataList.stream().collect(
                    Collectors.collectingAndThen(
                            Collectors.toCollection(() -> new TreeSet<>(Comparator.comparingLong(PaasFormDataEntityExt::getId))), ArrayList::new)
            );
            formDataRepeatVO.setFormDataList(dataEntityExts);
        } catch (Exception e) {
            LOG.error("导入查询数据重复出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return formDataRepeatVO;
    }
}
